package com.pocket.insight.base.mql;

import com.pocket.insight.base.mql.relation.BaseRelation;
import com.pocket.insight.base.mql.relation.JoinRelation;
import com.pocket.insight.base.mql.relation.StatementRelation;
import com.pocket.insight.base.sql.Dialect;
import com.pocket.insight.base.sql.Rewriter;
import com.pocket.insight.base.sql.SchemaProvider;
import com.pocket.insight.entity.ME;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.logging.log4j.util.Strings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * 描述：
 *
 * @author shuize
 * @create 2024/12/5
 */
public interface Relation {

    Logger log = LoggerFactory.getLogger(Relation.class);

    Relation setAlias(String alias);

    static StatementRelation statement(Dialect dialect) {
        return new StatementRelation(dialect);
    }

    static TypedVal evalWithRewrite(Relation relation, Dialect dialect) {
        LocalDateTime start = LocalDateTime.now();
        relation = Rewriter.applyAllRules(relation);
        LocalDateTime end = LocalDateTime.now();
        log.debug("Rewrite finish in {} ns ", Duration.between(start, end));
        return eval(relation, dialect);
    }

    static TypedVal eval(Relation relation, Dialect dialect) {
        if (relation != null) {
            if (relation instanceof StatementRelation && CollectionUtils.isEmpty(((StatementRelation) relation).select)){
                ((StatementRelation) relation).project(ME.create(ME.Kind.constant, ME.Star.STAR));
            } else if ((Strings.isNotEmpty(relation.getAlias()) || relation instanceof JoinRelation)){
                //return evalImpl((Relation) statement(relation.getDialect()).scan(relation).project(ME.create(ME.Kind.constant, ME.Star.STAR)), dialect);
                return null;
            }
        }
        return evalImpl(relation, dialect);
    }


    static TypedVal evalImpl(Relation relation, Dialect dialect) {
        if (relation.getIsSourceVirtualDialect(dialect).booleanValue()) {
            relation.setDialect(dialect);
        }
        TypedVal query = relation.toQuery();
        return query;
    }

    Boolean getIsSourceVirtualDialect(Dialect dialect);

    String getAlias();

    Long getRelationSize();

    Relation setRelationSize(Long size);

    BaseRelation.RelationRunTime fetchRunTime();

    TypedVal toQuery();

    Dialect getDialect();

    void setDialect(Dialect dialect);

    SchemaProvider getSchemaProvider();

    TypedVal getQueryForReused(TypedVal query, String alias, Boolean noNeedToReuse);

    void clearRunTime();

    default List<Relation> getWith() {
        return new ArrayList<>();
    }

    void setWithRecursive(Boolean withRecursive);

}
